package com.example.apisimpledy.utils;

import com.aliyun.oss.ClientException;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.OSSException;
import com.aliyun.oss.common.auth.CredentialsProviderFactory;
import com.aliyun.oss.common.auth.EnvironmentVariableCredentialsProvider;
import org.bytedeco.ffmpeg.avutil.AVRational;
import org.bytedeco.javacv.FFmpegFrameGrabber;
import org.bytedeco.javacv.Frame;
import org.bytedeco.javacv.Java2DFrameConverter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.time.Instant;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;

@Component
public class OssUtil {
    private static final Logger logger = LoggerFactory.getLogger(OssUtil.class);

    @Value("${aliyun.oss.file.endpoint}")
    String endpoint;

    @Value("${aliyun.oss.file.keyid}")
    String accessKeyId;

    @Value("${aliyun.oss.file.keysecret}")
    String accessKeySecret;

    @Value("${aliyun.oss.file.bucketname}")
    String bucketName;

    public String uploadFile(MultipartFile multipartFile, String userId, String videoId, String fileType) {
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
        try {
            InputStream inputStream = multipartFile.getInputStream();
            String originalFilename = multipartFile.getOriginalFilename();
            String fileExtension = originalFilename.substring(originalFilename.lastIndexOf('.'));
            String filename = videoId + "_" + userId + "_" + getCurrentTimestamp() + fileType + fileExtension;

            ossClient.putObject(bucketName, filename, inputStream);
            String url = "https://" + bucketName + "." + endpoint + "/" + filename;
            logger.info("File uploaded: {}", url);
            return url;

        } catch (Exception e) {
            e.printStackTrace();
            return null;
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
    }

    public String uploadImage(BufferedImage image, String userId, String videoId, String fileType) {
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
        try {
            ByteArrayOutputStream os = new ByteArrayOutputStream();
            ImageIO.write(image, "jpg", os);
            InputStream inputStream = new ByteArrayInputStream(os.toByteArray());
            String filename = videoId + "_" + userId + "_" + getCurrentTimestamp() + fileType + ".jpg";

            ossClient.putObject(bucketName, filename, inputStream);
            String url = "https://" + bucketName + "." + endpoint + "/" + filename;
            logger.info("Image uploaded: {}", url);
            return url;

        } catch (Exception e) {
            e.printStackTrace();
            return null;
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
    }

    public void deleteFile(String fileUrl) {
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);

        try {
            String objectName = fileUrl.substring(fileUrl.indexOf(bucketName) + bucketName.length() + 1);
            logger.info("Deleting object: {}", objectName);
            ossClient.deleteObject(bucketName, objectName);
            logger.info("File deleted: {}", fileUrl);
        } catch (OSSException oe) {
            logger.error("Caught an OSSException, which means your request made it to OSS, but was rejected with an error response for some reason.");
            logger.error("Error Message: " + oe.getErrorMessage());
            logger.error("Error Code: " + oe.getErrorCode());
            logger.error("Request ID: " + oe.getRequestId());
            logger.error("Host ID: " + oe.getHostId());
            throw new RuntimeException("Failed to delete file from OSS", oe);
        } catch (ClientException ce) {
            logger.error("Caught an ClientException, which means the client encountered a serious internal problem while trying to communicate with OSS, such as not being able to access the network.");
            logger.error("Error Message: " + ce.getMessage());
            throw new RuntimeException("Failed to delete file from OSS", ce);
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
    }

    public BufferedImage grabFirstFrame(MultipartFile videoFile) throws Exception {
        InputStream videoFileStream = videoFile.getInputStream();
        FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(videoFileStream);
        grabber.start();

        Frame frame = grabber.grabImage();
        if (frame == null) {
            throw new IllegalArgumentException("无法获取视频的第一帧，请确保上传的文件是视频格式。");
        }

        Java2DFrameConverter converter = new Java2DFrameConverter();
        BufferedImage image = converter.convert(frame);

        grabber.stop();
        grabber.release();
        videoFileStream.close();

        return image;
    }

    public int getVideoDuration(MultipartFile videoFile) throws Exception {
        InputStream videoFileStream = videoFile.getInputStream();
        FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(videoFileStream);
        grabber.start();

        int lengthInSeconds = (int) (grabber.getLengthInTime() / (double) 1000000);

        grabber.stop();
        grabber.release();
        videoFileStream.close();

        return lengthInSeconds;
    }

    private String getCurrentTimestamp() {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMddHHmmss").withZone(ZoneId.systemDefault());
        return formatter.format(Instant.now());
    }
}
